package nz.ac.massey.spidernetpn.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseWheelListener;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;


import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.collections15.Transformer;

import nz.ac.massey.spidernetpn.database.GraphDatabase;
import nz.ac.massey.spidernetpn.gui.MainGui.LoadThread;
import nz.ac.massey.spidernetpn.webcrawler.FoundMaxException;
import nz.ac.massey.spidernetpn.webcrawler.WebCrawler;
import edu.uci.ics.jung.algorithms.layout.*;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.algorithms.layout.util.VisRunner;
import edu.uci.ics.jung.algorithms.util.IterativeContext;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.ObservableGraph;
import edu.uci.ics.jung.graph.event.GraphEvent;
import edu.uci.ics.jung.graph.event.GraphEventListener;
import edu.uci.ics.jung.graph.util.Graphs;
import edu.uci.ics.jung.visualization.BasicVisualizationServer;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.AbstractModalGraphMouse;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.layout.LayoutTransition;
import edu.uci.ics.jung.visualization.renderers.*;
import edu.uci.ics.jung.visualization.util.Animator;

public class GuiPrototype extends JPanel implements GuiInterface {
	private static final long serialVersionUID = 6962983038658967662L;
	Thread loadThread;
	Object lock = new Object();
	private static WebCrawler crawler = new WebCrawler(true);
	private JFrame frame = new JFrame("Web-Clawer");
	private String name;
	private JTextField urlField;
	private JTextField numField;
	private JProgressBar progressBar;
	private static JButton  stopButton;
	private GraphDatabase gDB = new GraphDatabase();
	public static MainGui main = new MainGui();
	private DirectedGraph<URL,Integer> graph;
	boolean shouldStop = false;
	JTextField progressTextField;
	JFrame GraphFrame = new JFrame("Simple Graph View");
	JPanel GraphPanel = new JPanel();
	VisualizationViewer<URL, Integer> vv;
	JPanel drawingPane;
	
	public void Frame() {
		// TODO Auto-generated method stub
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setJMenuBar(createMenuBar());
		frame.getContentPane().add(graphPane(),BorderLayout.CENTER);
		frame.getContentPane().add(createProgressBar(),BorderLayout.SOUTH);
		frame.pack();
		frame.setSize(900, 700);
		frame.setVisible(true);	
	}
		
	public JPanel graphPane(){
		Dimension area;
		area = new Dimension(50,50);
		drawingPane = new DrawingPane();
	    JScrollPane scroller = new JScrollPane(drawingPane);
	    scroller.setPreferredSize(new Dimension(600,500));    
		return drawingPane;
		
	}
	
	 public class DrawingPane extends JPanel {
	        protected void paintComponent(Graphics g) {
	            super.paintComponent(g);    
	            crawler.addActionListener(new ActionListener() {
	    			@Override
	    			public void actionPerformed(ActionEvent e) {
	    				//get the DirectedGraph
	    				graph = crawler.getGraph();
	    				//Draw the graph and display it
	    				//System.out.println("Drawn something new I hope. Size: " + graph.getEdgeCount());
	    				
	    				if((graph.getEdgeCount()%100==0)||(graph.getEdgeCount()<10&&graph.getEdgeCount()>1)){
		    				System.out.println("An action has been called");
		    				drawingPane.removeAll();
		    				Drawing(graph);

	    				}
	    				if(graph.getEdgeCount()>201){
	    					//FOr testing stop after 200 nodes
	    					crawler.pause();
	    				}

	    			}
	    		});
	        }
	    }
	 
	 Random rand = new Random();
	 public Paint nodeColor = new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255));
		
	 public void Drawing(DirectedGraph<URL, Integer> g) {	
		 
		 	FRLayout2<URL,Integer> layout = new FRLayout2<URL, Integer>(g);
			layout.setSize(new Dimension(400,400)); // sets the initial size of the layout space
			Dimension preferredSize = new Dimension(500,500);

			Transformer<URL, String> nodeLabelTransform =
				new Transformer<URL, String>()
			{
				public String transform(URL url) {
					String str = nodeLabelConvert(url);
					return str;
				}
			};
			
			Transformer<URL, Paint> nodeColorTransform =
				new Transformer<URL, Paint>()
			{
				public Paint transform(URL url) {
					Boolean bool = false;
					
					List nodeList = new ArrayList<String>();
					List colorList = new ArrayList<Paint>();
					if (!nodeList.isEmpty()){
						while (nodeList.listIterator().hasNext() && bool==false){
							//if the new node name is found in list,
							//the colour of new node will set to be same as the group it belong to.
							if (url.toString() == nodeList.toString()){
								bool=true;
								
								return nodeColor;
							}
						}
						if (bool==false){
							//if the new node name is not found in list,
							//then a new colour is given to the new node
							return nodeColor;
						}
					}
					//The first node is given a random colour.
					Paint nColor = nodeColor;
					colorList.add(nColor);
					return nodeColor;
				}
			};
			

			
		    vv = new VisualizationViewer<URL, Integer>(layout, preferredSize);
			vv.getRenderContext().setVertexLabelTransformer(nodeLabelTransform);
			vv.getRenderContext().setVertexFillPaintTransformer(nodeColorTransform);
			final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();
	        vv.setGraphMouse(graphMouse);
	        vv.addKeyListener(graphMouse.getModeKeyListener());
			vv.repaint();
			vv.setVisible(true);
			drawingPane.add(vv);
			
	 }
	 
		public String nodeLabelConvert(URL url){
			String nodename="";
			String nodeURL = url.toString();
			String [] splitstring = nodeURL.split("/");
			for (String s : splitstring)
			{
				nodename=splitstring[2];
			}
			return nodename;
		}
		
		
	public JMenuBar createMenuBar() {
		// TODO Auto-generated method stub	
		JMenuBar menuBar = new JMenuBar();
		// Define and add two drop down menu to the menubar
		JMenu fileMenu = new JMenu("File");
		JLabel Url = new JLabel("Enter url: ");
		JLabel limitLabel = new JLabel("Max no.URL to search");
		urlField = new JTextField();
		numField = new JTextField();
		urlField.setText("http://www.google.com");
		urlField.setColumns(20);
		numField.setColumns(1);
		JButton goButton = new JButton("Go");
		stopButton = new JButton("Stop");
		menuBar.add(fileMenu);
		menuBar.add(Url);
		menuBar.add(urlField);
		menuBar.add(limitLabel);
		menuBar.add(numField);
		menuBar.add(goButton);
		menuBar.add(stopButton);
		
		// Create and add simple menu item to one of the drop down menu
		JMenuItem newAction = new JMenuItem("New");
		JMenuItem openAction = new JMenuItem("Open");
		JMenuItem saveAction = new JMenuItem("Save");
		JMenuItem exitAction = new JMenuItem("Exit");
		fileMenu.add(newAction);
		fileMenu.add(openAction);
		fileMenu.add(saveAction);
		fileMenu.addSeparator();
		fileMenu.add(exitAction);

		goButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				start();
				startLoading();
			}
		});
		
		stopButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				crawler.pause();
				main.stopLoading();
			}
		});

		saveAction.addActionListener(new ActionListener() {
			@SuppressWarnings("deprecation")
			public void actionPerformed(ActionEvent e1){
				JFrame saveFrame = new JFrame();
		        JTextField field = new JTextField();
		        JButton ok = new JButton("OK");
		        JLabel note = new JLabel("Please give a name for graph to save");
 		        saveFrame.setSize(550, 30);
		        field.setSize(500, 30);
		        saveFrame.add(note, BorderLayout.NORTH);
		        saveFrame.add(field);
		        saveFrame.add(ok, BorderLayout.EAST);
			   // saveFrame.setVisible(true);
			    saveFrame.pack();
			    saveFrame.show();
				name = field.getText();
				ok.addActionListener(new ActionListener(){
					public void actionPerformed(ActionEvent e2){
							if (gDB.saveGraph(name, graph)){
								JOptionPane.showMessageDialog(frame, "Save succeed");
							}
							else {
									JOptionPane.showMessageDialog(frame,
									"Error on saving or missing the saving name of graph","Error", 
									JOptionPane.ERROR_MESSAGE);
							}
					}
					}
				);
			}
		});
		
		openAction.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e1) {
				final DefaultListModel listModel = new DefaultListModel();			
				JFrame loadFrame = new JFrame();
		       // JTextField field = new JTextField();    
		        JButton load = new JButton("Load");
		        final JButton remove = new JButton("Remove");
		        loadFrame.setSize(550, 300);
		       //field.setSize(500, 300);
		       //loadFrame.add(field, BorderLayout.NORTH);
		        loadFrame.add(load, BorderLayout.CENTER);
		        loadFrame.add(remove, BorderLayout.SOUTH);
			    
				List gList = gDB.getListOfStoredGraphs();
				//System.out.println("Here"+gList);
				
				if (!gList.isEmpty()){
					Iterator graphListIter = gList.iterator();
					
					while (graphListIter.hasNext())
					{
						//System.out.println("looping");
						Object obj = graphListIter.next();
						listModel.addElement(obj.toString());			
					}
				}
				//System.out.println("Done Here");
				final JList L = new JList(listModel);
				L.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		        L.setSelectedIndex(0);
		        L.addListSelectionListener(null);
		        L.setVisibleRowCount(5);
		        JScrollPane listScrollPane = new JScrollPane(L);
		        loadFrame.add(listScrollPane, BorderLayout.NORTH);
		        loadFrame.pack();
			    loadFrame.show();
		        
		        //remove method
				remove.addActionListener(new ActionListener(){
					public void actionPerformed(ActionEvent e) {
			            int index = L.getSelectedIndex();
			            listModel.remove(index);

			            int size = listModel.getSize();

			            if (size == 0) { //Nobody's left, disable removing.
			                remove.setEnabled(false);

			            } else { //Select an index.
			                if (index == listModel.getSize()) {
			                    //removed item in last position
			                    index--;
			                }

			                L.setSelectedIndex(index);
			                L.ensureIndexIsVisible(index);
			            }
			        }
				});
				
				//get a name from the list
				String name = listModel.getElementAt(
                              L.getSelectedIndex()).toString();
	
				//Display the selected graph
				DirectedGraph<URL, Integer> savedGraph = null;
				try {
					savedGraph = gDB.loadCustomGraph(name);
					Drawing(savedGraph);
					
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				}
		});

		exitAction.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				System.exit(0);
			}
		});
		return menuBar;
	}
	
	
	public JPanel createProgressBar() {
		// TODO Auto-generated method stub
		JPanel panel = new JPanel();
		JTextField progressTextField = new JTextField();
		progressBar = new JProgressBar();
		progressBar.setStringPainted(true);

		panel.setLayout(new GridLayout(0, 1));
		panel.add(new JLabel("Load Status"));
		panel.add(progressBar, BorderLayout.SOUTH);
		return panel;
	}



	public String url() {
		// TODO Auto-generated method stub
		return urlField.getText();
	}
	

	public void start(){
		try {
			crawler.submit(url());
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (FoundMaxException e) {
			e.printStackTrace();
		}
	}

	public void startLoading() {
		if (loadThread == null) {
			loadThread = new LoadThread();
			shouldStop = false;
			loadThread.start();
			validate();
		}
	}

	class LoadThread extends Thread {
		public void run() {
			int min = 0;
			int max = 100;
			progressBar.setValue(min);
			progressBar.setMinimum(min);
			progressBar.setMaximum(max);
			Runnable runner = new Runnable() {
				public void run() {
					int value = progressBar.getValue();
					value++;
					progressBar.setValue(value);
					progressTextField.setText("" + value);
				}
			};
			for (int i = min; i <= max; i++) {
				try {
					SwingUtilities.invokeAndWait(runner);
				} catch (InvocationTargetException e) {
					break;
				} catch (InterruptedException e) {
					// Ignore Exception
				}
				synchronized (lock) {
					if (shouldStop)
						break;
					try {
						lock.wait(100);
					} catch (InterruptedException e) {
						// Ignore Exception
					}
				}
			}
			loadThread = null;
		}
	}
	
	
	/**
	 * @param args
	 */

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		final GuiPrototype a = new GuiPrototype();
		a.Frame();
	}

}
